/**
 * @description: Promise
 * @author: huen2015
 */
interface IAllSettledResult<T> {
	status: string
	value?: T
	reason?: T
	index?: number
}

function PromiseAll<T = any>(args: Promise<T>[]): Promise<T | T[] | never> {
	if (args == null || (args && args.length === 0))
		return Promise.reject('args 必须为数组')

	return new Promise((resolve, reject) => {
		const result: T[] = []
		args.forEach((p: Promise<T>) => {
			p.then((res) => {
				result.push(res)
				if (result.length === args.length) {
					resolve(result)
				}
			}).catch((err) => {
				reject(err)
			})
		})
	})
}

function PromiseRace<T = any>(args: Promise<T>[]): Promise<T | T[] | never> {
	if (args == null || (args && args.length === 0))
		return Promise.reject('args 必须为数组')

	return new Promise((resolve, reject) => {
		args.forEach((p: Promise<T>) => {
			p.then((res) => {
				resolve(res)
			}).catch((err) => {
				reject(err)
			})
		})
	})
}

function PromiseAllSettled<T = any>(
	args: Promise<T>[],
): Promise<T | T[] | IAllSettledResult<T>[] | never> {
	if (args == null || (args && args.length === 0))
		return Promise.reject('args 必须为数组')

	return new Promise((resolve) => {
		let result: IAllSettledResult<T>[] = []
		args.forEach((p: Promise<T>, index: number) => {
			p.then((res) => {
				result.push({
					status: 'fulfilled',
					value: res,
					index: index + 1,
				})
			})
				.catch((err) => {
					result.push({
						status: 'fulfilled',
						reason: err,
						index: index + 1,
					})
				})
				.finally(() => {
					if (result.length === args.length) {
						result = result
							.sort(
								(
									a: IAllSettledResult<T>,
									b: IAllSettledResult<T>,
								) => {
									if (a.index && b.index) {
										return a.index - b.index
									} else {
										return 0
									}
								},
							)
							.map((item) => {
								return {
									status: item.status,
									value: item.value,
								}
							})
						resolve(result)
					}
				})
		})
	})
}

const p1 = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve('p1')
	}, 300)
})
const p2 = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve('p2')
	}, 300)
})
const p3 = Promise.reject('p3')
// PromiseAll([p1, p2, p3])
//     .then(res => {
//         console.log('PromiseAll - then', res)
//     }).catch(err => {
//         console.log('PromiseAll - catch', err)
//     }).finally(() => {
//         console.log('PromiseAll.finally')
//     })
// Promise.all([p1, p2, p3])
//     .then(res => {
//         console.log('Promise.all - then', res)
//     }).catch(err => {
//         console.log('Promise.all - catch', err)
//     }).finally(() => {
//         console.log('Promise.finally')
//     })

// PromiseRace([p1, p2, p3])
//     .then(res => {
//         console.log('PromiseRace - then', res)
//     }).catch(err => {
//         console.log('PromiseRace - catch', err)
//     })
// Promise.race([p1, p2, p3])
//     .then(res => {
//         console.log('Promise.race - then', res)
//     }).catch(err => {
//         console.log('Promise.race - catch', err)
//     })

PromiseAllSettled([p1, p2, p3]).then((res) => {
	console.log('PromiseAllSettled - then', res)
})
Promise.allSettled([p1, p2, p3])
	.then((res) => {
		console.log('Promise.allSettled - then', res)
	})
	.catch((err) => {
		console.log('Promise.allSettled - catch', err)
	})
	.finally(() => {
		//console.log('Promise.finally')
	})

export {}
